(function(){
    "use strict";

    angular.module("zhxValidate", []);

    /**
     * ZHX Validate Frame ( customValidate )
     * Author:  Vicco Wang
     * Date:    2016-08-11
     *
     * 前端 基于Angular 1.x 验证框架
     *
     * 本框架依赖于:
     * AngularJS
     * Layer 弹出层组件
     *
     * 支持以下验证:
     *
     * required         //必填
     * maxLength        //字符最大长度
     * minLength        //字符最小长度
     * remout          //远程验证
     * equalTo          //与某值保持一致
     * equalToScopeVal  //与Form Scope 中的某个值保持一致
     * number           //数字
     * idCard           //身份证号码（支持15或18位）
     * char             //英文字母
     * mobile           //手机号
     * account          //字母数字下划线
     * email            //标准邮件地址
     * date             //标准YYYY-MM-DD日期格式
     * url              //标准URL地址
     * chinese          //中文字符
     *
     * 支持自定义验证文字，格式为
     * { validateKEY : { value : validateValue, message : validateMessage } }
     * 也就是验证字段的KEY 为一个 KEY&VALUE格式的对象，KEY必须为value,message,其中的验证的内容使用$符进行替换，详情请见下面的示例
     *
     * 使用示例:
     *
     *  <input type="text" name="test" ng-model="test.input" custom-validate="required" />
     *  或
     *  <input type="text" name="test" ng-model="test.input" custom-validate="{ required : true }" />
     *  或多个同时验证:
     *  <input type="text" name="test" ng-model="test.input" custom-validate="{ required : true, maxlength: 10, equalToScopeVal : 'someValue'  }" />
     *
     *  远程验证:
     *  key : remout
     *  value : [ url, {scope data} ]
     *  <input type="text" name="test" ng-model="test.input" custom-validate="{ remout : ['somePath/remoutValidate', 'scopeData' }" />
     *
     *  自定义验证文字
     *  <input type="text" name="test" ng-model="test.input" custom-validate="{ minLength : { value : 10, message: '长度不够$位啊，亲~' }  }" />
     *  //输出的值为：长度不够10位啊，亲~
     *
     */

    /**
     * 验证框架支持库服务
     */
    angular.module("zhxValidate").factory("zhxValidateLib", ["$timeout","$http","$q",function($timeout,$http,$q){

        var time = null;

        var validateLib = {

             addValidate : function(ngScope, ngController, validateType, validateValue ){

                 ngController.$parsers.unshift(function (viewValue) {

                     switch (validateType) {

                         //非空验证
                         case 'required':
                             if ( viewValue.trim().length ) {
                                 ngController.$setValidity('required', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('required', false);
                                 return undefined;
                             }
                             break;

                         //远程验证
                         case 'remout' :
                             if(time) $timeout.cancel(time);
                              time = $timeout(function(){
                                  if( validateValue ){
                                      if( angular.isObject( validateValue ) && !angular.isArray( validateValue ) ){
                                          validateValue = validateValue['value'];
                                      };
                                      var param = eval('ngScope.$parent.' + validateValue[1] );
                                      $http.post(validateValue[0],param).then(function(res){
                                          if( res.data.code == "200" ){
                                              ngController.$setValidity('remout', true);
                                              return viewValue;
                                          } else {
                                              ngController.$setValidity('remout', false);
                                              return undefined;
                                          }
                                      });

                                  }
                              },300);
                             return viewValue;
                             break;

                         //与某值保持一致
                         case 'equalTo' :
                             if( validateValue ){
                                 if( angular.isObject( validateValue ) && !angular.isArray( validateValue ) ){
                                     validateValue = validateValue['value'];
                                 };
                                 if( viewValue.trim() === validateValue ){
                                     ngController.$setValidity('equalTo', true);
                                     return viewValue;
                                 } else {
                                     ngController.$setValidity('equalTo', false);
                                     return undefined;
                                 }
                             }
                             break;

                         //与Form Scope 中的某个值保持一致
                         case 'equalToScopeVal' :
                             //ngScope.$parent 为父作用域。表示查找父作用域下的某值
                             if( angular.isObject( validateValue ) && !angular.isArray( validateValue ) ){
                                 validateValue = validateValue['value'];
                             };
                             var scopeValue = eval('ngScope.$parent.' + validateValue);
                             if( angular.isUndefined( scopeValue ) ) return false;
                             if( viewValue.trim() == scopeValue ){
                                 ngController.$setValidity('equalToScopeVal', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('equalToScopeVal', false);
                                 return undefined;
                             }
                             break;

                         //最大长度
                         case 'maxLength' :
                             if( validateValue ){
                                 if( angular.isObject( validateValue ) && !angular.isArray( validateValue ) ){
                                     validateValue = validateValue['value'];
                                 };
                                 if( viewValue.length <= validateValue ){
                                     ngController.$setValidity('maxLength', true);
                                     return viewValue;
                                 } else {
                                     ngController.$setValidity('maxLength', false);
                                     return undefined;
                                 }
                             }
                             break;

                         //最小长度
                         case 'minLength' :
                             if( validateValue ){
                                 if( angular.isObject( validateValue ) && !angular.isArray( validateValue ) ){
                                     validateValue = validateValue['value'];
                                 };
                                 if( viewValue.length >= validateValue ){
                                     ngController.$setValidity('minLength', true);
                                     return viewValue;
                                 } else {
                                     ngController.$setValidity('minLength', false);
                                     return undefined;
                                 }
                             }
                             break;

                         //手机号
                         case 'mobile':
                             var pattern = /^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('mobile', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('mobile', false);
                                 return undefined;
                             }
                             break;

                         //数字
                         case 'number':
                             var pattern = /^([0-9]+)$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('number', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('number', false);
                                 return undefined;
                             }
                             break;

                         //身份证
                         case 'idCard':
                             var pattern = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('idCard', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('idCard', false);
                                 return undefined;
                             }
                             break;

                         //英文字母
                         case 'char':
                             var pattern = /^([a-zA-Z]+)$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('char', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('char', false);
                                 return undefined;
                             }
                             break;

                         //字母+数字+下划线
                         case 'account':
                             var pattern = /^([a-zA-Z0-9_]+)$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('account', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('account', false);
                                 return undefined;
                             }
                             break;

                         //E-mail
                         case 'email':
                             var pattern = /^([a-zA-Z0-9]+[_|\-|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\-|\.]?)*[a-zA-Z0-9]+(\.[a-zA-Z]{2,3})+$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('email', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('email', false);
                                 return undefined;
                             }
                             break;

                         //标准YYYY-MM-DD格式日期
                         case 'date':
                             var pattern = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('date', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('date', false);
                                 return undefined;
                             }
                             break;

                         //标准URL地址
                         case 'url':
                             var pattern = /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('url', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('url', false);
                                 return undefined;
                             }
                             break;

                         //中文
                         case 'chinese':
                             var pattern = /^[\u4e00-\u9fa5]+$/;
                             if (pattern.test(viewValue)) {
                                 ngController.$setValidity('chinese', true);
                                 return viewValue;
                             } else {
                                 ngController.$setValidity('chinese', false);
                                 return undefined;
                             }
                             break;
                     }

                 })

             },

             getValidateText : function( parseObject, userValidateObject ){


                 var validateMessage = {
                     required           : "该字段不能为空",
                     maxLength          : "最大长度{0}个字符",
                     minLength          : "最小长度{0}个字符",
                     remout             : "验证数据失败",
                     equalTo            : "与值{0}未保持一致",
                     equalToScopeVal    : "值未保持一致",
                     mobile             : "填写的手机号码格式有误",
                     number             : "该字段只能填写数字",
                     idCard             : "身份证号码格式有误",
                     char               : "该字段只能填写字母",
                     account            : "用户名必须为字母数字下划线组合",
                     chinese            : "必须填写中文",
                     normal             : "验证有误"
                 };

                 var validateTextArray = [];

                 angular.forEach( parseObject, function( value, key ){
                     if( !angular.isUndefined( validateMessage[key] ) && value ){
                         var msg = '',valueObject = userValidateObject[key];
                         if( angular.isObject( valueObject ) && !angular.isArray( valueObject ) && !angular.isString( valueObject ) ){
                             msg = valueObject['message'];
                             msg = msg.replace(/\{(\d+)\}/g, function(match,number){
                                  return valueObject['value'];
                             } );
                         } else {
                            msg = validateMessage[key];
                            msg = msg.replace(/\{(\d+)\}/g, function(match,number){
                                return userValidateObject[key];
                            } );
                         }
                         validateTextArray.push( msg );
                     }
                 });

                 var parseValidateMsg = "",dot = "";
                 for( var i = 0; i < validateTextArray.length; i++ ){
                     if( validateTextArray.length > 1 ){
                         dot = ", ";
                         if( i == validateTextArray.length - 1 ) dot = "";
                     }
                     parseValidateMsg += validateTextArray[i] + dot;
                 };

                 return parseValidateMsg;

             }

         };

         return validateLib;

    }]);


    angular.module("zhxValidate").directive("customValidate", ["$timeout","zhxValidateLib","$q",function($timeout,zhxValidateLib,$q){
        return {
            restrict : 'A',
            scope : true,
            require : '^ngModel',
            compile : function( element ){

                return {
                    post : function( scope, element, attr, ngCtrl ){

                        //基础验证类型
                        var validateType = attr.customValidate;

                        var validateObject = scope.$eval(validateType);

                        //如果是字符型验证，则为字符串，这里判断为undefined
                        if( angular.isUndefined( validateObject ) ){
                            //添加验证
                            zhxValidateLib.addValidate( scope, ngCtrl, validateType );

                            validateObject = new Object();
                            validateObject[validateType] = true;

                            //如果是对象型验证，则为Object
                        } else {
                            angular.forEach( validateObject, function(value, key){
                                //向ngModel $parsers 添加验证方法
                                if( value ) zhxValidateLib.addValidate( scope, ngCtrl, key, value );
                            });
                        }


                        //设置提示Tip的Index，用于关闭使用
                        var layerIdx = null;
                        var timeout = null;


                        element.on('keyup',function(){

                            var me = this;

                            $timeout.cancel(timeout);

                            timeout = $timeout(function(){

                                if(  ngCtrl.$invalid ){

                                    //根据类型获取验证后的提示信息
                                    var invalidText = zhxValidateLib.getValidateText( ngCtrl.$error, validateObject );

                                    if( layerIdx == null && invalidText.trim().length ){

                                        layerIdx = layer.open({
                                            type : 4,                       //TIP
                                            tips: [1, '#c9302c'],           //在上面弹出 并设置为 红色
                                            shift : 5,                      //使用弹出动画
                                            content : [ invalidText , me ], //TIP内容
                                            skin : 'customValidateLayer',   //自定义一个样式，暂未启用
                                            closeBtn : 0,                   //不显示关闭按钮
                                            shade: 0,                       //不显示遮罩
                                            //time:4000,                      //设置一个时间
                                            tipsMore: true,                  //因为是验证提示，允许页面同时弹出多个TIP
                                            end : function(){
                                                layerIdx = null;
                                            }
                                        });

                                    }

                                } else {
                                    layer.close(layerIdx);
                                    layerIdx = null;
                                }

                            },450);

                        });

                        //如果当前作用域被移除，例如弹出层被移除，则自动移除当前layer层
                        scope.$on('$destroy',function(ev,arg){
                            layer.close(layerIdx);
                            layerIdx = null;
                        })

                    }
                }
            }
        }

    }]);


})()


